home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1994 August: Tool Chest / Dev.CD Aug 94.toast / Tool Chest / Games / Game Sample Code / SpriteWorld 1.0b3 / Sources / SpriteWorldUtils.c < prev   
Encoding:
Text File  |  1993-06-16  |  31.3 KB  |  1,335 lines  |  [TEXT/KAHL]

  1. ///--------------------------------------------------------------------------------------
  2. //    SpriteWorldUtils.c
  3. //
  4. //    Created:    Monday, January 18, 1993 at 8:57:36 PM
  5. //    By:        Tony Myles
  6. //
  7. //    Copyright: © 1993 Tony Myles, All rights reserved worldwide.
  8. //
  9. //    Description:    some utilities for creating worlds of sprites
  10. ///--------------------------------------------------------------------------------------
  11.  
  12.  
  13. #ifndef __QUICKDRAW__
  14. #include <QuickDraw.h>
  15. #endif
  16.  
  17. #ifndef __QDOFFSCREEN__
  18. #include <QDOffscreen.h>
  19. #endif
  20.  
  21. #ifndef __MEMORY__
  22. #include <Memory.h>
  23. #endif
  24.  
  25. #ifndef __GESTALTEQU__
  26. #include <GestaltEqu.h>
  27. #endif
  28.  
  29. #ifndef __TOOLUTILS__
  30. #include <ToolUtils.h>
  31. #endif
  32.  
  33. #ifndef __RESOURCES__
  34. #include <Resources.h>
  35. #endif
  36.  
  37. #ifndef __ERRORS__
  38. #include <Errors.h>
  39. #endif
  40.  
  41. #ifndef __SPRITEWORLD__
  42. #include <SpriteWorld.h>
  43. #endif
  44.  
  45. #ifndef __SPRITELAYER__
  46. #include <SpriteLayer.h>
  47. #endif
  48.  
  49. #ifndef __SPRITE__
  50. #include <Sprite.h>
  51. #endif
  52.  
  53. #ifndef __FRAME__
  54. #include <Frame.h>
  55. #endif
  56.  
  57. #ifndef __SPRITEWORLDUTILS__
  58. #include <SpriteWorldUtils.h>
  59. #endif
  60.  
  61.  
  62. ///--------------------------------------------------------------------------------------
  63. // SWCreateBestCGrafPort                                        Adapted from code by Forrest Tanaka
  64. ///--------------------------------------------------------------------------------------
  65.  
  66. SW_PASCAL OSErr SWCreateBestCGrafPort(
  67.     CGrafPtr    *newCGrafPort,                    // returns a pointer to the new CGrafPort
  68.     Rect        *offScreenRect)                // global rectangle of part of screen to save
  69. {
  70.     OSErr                err;                        // err code
  71.     GDHandle            baseGDevice;            // GDevice to base off-screen on
  72.     PixMapHandle    basePixMap;                // baseGDevice’s PixMap
  73.     Rect                tempOffScreenRect;    // temp rect used for adjustments
  74.  
  75.     err = noErr;
  76.  
  77.         // graphics devices manager tells us the deepest intersecting screen
  78.     baseGDevice = GetMaxDevice(offScreenRect);
  79.  
  80.         // if no screens intersect the bounds, baseDevice is NULL
  81.     if ((baseGDevice != NULL) && (err == noErr))
  82.     {
  83.             // normalize the bounds rectangle
  84.         tempOffScreenRect = *offScreenRect;
  85.         OffsetRect(&tempOffScreenRect, -tempOffScreenRect.left, -tempOffScreenRect.top);
  86.  
  87.             // create off-screen graphics environment w/ depth, clut of screen
  88.         basePixMap = (**baseGDevice).gdPMap;
  89.         err = SWCreateCGrafPort(newCGrafPort, &tempOffScreenRect, (**basePixMap).pixelSize,
  90.                                 (**basePixMap).pmTable, baseGDevice);
  91.     }
  92.  
  93.     return err;
  94. }
  95.  
  96.  
  97. ///--------------------------------------------------------------------------------------
  98. // SWCreateOffScreen                                                Adapted from code by Forrest Tanaka
  99. ///--------------------------------------------------------------------------------------
  100.  
  101. #define kMaxRowBytes 0x3FFE // Maximum number of bytes in a row of pixels
  102.  
  103. SW_PASCAL OSErr SWCreateCGrafPort(
  104.     CGrafPtr        *newCGrafPort,        // returns a pointer to the new CGrafPort
  105.     Rect            *bounds,                // bounding rectangle of off-screen
  106.     short            depth,                // desired number of bits per pixel in off-screen
  107.     CTabHandle    colors,                // color table to assign to off-screen
  108.     GDHandle        useGDevice)            // returns a handle to the new GDevice
  109. {
  110.     CGrafPtr            tempCGrafPort;    // pointer to the new off-screen CGrafPort
  111.     PixMapHandle    newPixMap;        // handle to the new off-screen PixMap
  112.     GDHandle            newDevice;        // handle to the new off-screen GDevice
  113.     long                qdVersion;        // version of QuickDraw currently in use
  114.     GrafPtr            savedPort;        // pointer to GrafPort used for save/restore
  115.     SignedByte        savedState;        // saved state of color table handle
  116.     short                bytesPerRow;    // number of bytes per row in the PixMap
  117.     OSErr                err;                // returns err code
  118.  
  119.         // initialize a few things before we begin
  120.     tempCGrafPort = NULL;
  121.     newPixMap = NULL;
  122.     newDevice = NULL;
  123.     err = noErr;
  124.  
  125.         // save the color table’s current state and make sure it isn’t purgeable
  126.     if (colors != NULL)
  127.     {
  128.         savedState = HGetState( (Handle)colors );
  129.         HNoPurge( (Handle)colors );
  130.     }
  131.  
  132.         // calculate the number of bytes per row in the off-screen PixMap
  133.     bytesPerRow = ((depth * (bounds->right - bounds->left) + 31) >> 5) << 2;
  134.  
  135.         // get the current QuickDraw version
  136.     err = Gestalt(gestaltQuickdrawVersion, &qdVersion);
  137.  
  138.         // this will always be noErr, but I can't stand not checking anyway!
  139.     if (err == noErr)
  140.     {
  141.             // make sure depth is indexed or depth is direct and 32-Bit QD installed
  142.         if (depth == 1 || depth == 2 || depth == 4 || depth == 8 ||
  143.             ((depth == 16 || depth == 32) && qdVersion >= gestalt32BitQD))
  144.         {
  145.                 // maximum number of bytes per row is 16,382; make sure within range
  146.             if (bytesPerRow <= kMaxRowBytes)
  147.             {
  148.                     // make sure a color table is provided if the depth is indexed
  149.                 if (depth <= 8)
  150.                     if (colors == NULL)
  151.                             // indexed depth and clut is NIL; is parameter err
  152.                         err = paramErr;
  153.                 }
  154.             else
  155.                     // # of bytes per row is more than 16,382; is parameter err
  156.                 err = paramErr;
  157.         }
  158.         else
  159.                 // pixel depth isn’t valid; is parameter err
  160.             err = paramErr;
  161.     }
  162.  
  163.         // if sanity checks succeed, then allocate a new CGrafPort
  164.     if (err == noErr)
  165.     {
  166.         tempCGrafPort = (CGrafPtr)NewPtr(sizeof (CGrafPort) );
  167.         if (tempCGrafPort != NULL)
  168.         {
  169.                 // save the current port
  170.             GetPort( &savedPort );
  171.  
  172.                 // initialize the new CGrafPort and make it the current port
  173.             OpenCPort( tempCGrafPort );
  174.  
  175.                 // set portRect, visRgn, and clipRgn to the given bounds rect
  176.             tempCGrafPort->portRect = *bounds;
  177.             RectRgn( tempCGrafPort->visRgn, bounds );
  178.             ClipRect( bounds );
  179.  
  180.                 // initialize the new PixMap for off-screen drawing
  181.             err = SWSetUpPixMap(tempCGrafPort->portPixMap, depth, bounds, colors, bytesPerRow);
  182.  
  183.             if (err == noErr)
  184.             {
  185.                 EraseRect(bounds);
  186.  
  187.                     // grab the initialized PixMap handle
  188.                 newPixMap = tempCGrafPort->portPixMap;
  189.             }
  190.  
  191.                 // restore the saved port
  192.             SetPort(savedPort);
  193.         }
  194.         else
  195.             err = MemError();
  196.     }
  197.  
  198.         // restore the given state of the color table
  199.     if (colors != NULL)
  200.         HSetState((Handle)colors, savedState);
  201.  
  202.         // one last look around the house before we go...
  203.     if (err != noErr)
  204.     {
  205.             // some err occurred; dispose of everything we allocated
  206.         if (newPixMap != NULL)
  207.         {
  208.             DisposCTable((**newPixMap).pmTable);
  209.             DisposPtr((**newPixMap).baseAddr);
  210.         }
  211.  
  212.         if (tempCGrafPort != NULL)
  213.         {
  214.             CloseCPort(tempCGrafPort);
  215.             DisposPtr((Ptr)tempCGrafPort);
  216.         }
  217.     }
  218.     else
  219.     {
  220.             // everything’s OK; return refs to off-screen CGrafPort
  221.         *newCGrafPort = tempCGrafPort;
  222.     }
  223.  
  224.     return err;
  225. }
  226.  
  227.  
  228. ///--------------------------------------------------------------------------------------
  229. // SWCreateCGrafPortFromCIconMask
  230. ///--------------------------------------------------------------------------------------
  231.  
  232. SW_PASCAL OSErr SWCreateCGrafPortFromCIconMask(
  233.     CGrafPtr *newCGrafPort,
  234.     CIconHandle cIconH)
  235. {
  236.     OSErr err;
  237.     GrafPtr savePort;
  238.     char saveState;
  239.     CGrafPtr tempCGrafPort;
  240.     BitMap maskBitMap;
  241.     PixMapHandle maskPixMapH;
  242.  
  243.     *newCGrafPort = NULL;
  244.  
  245.     GetPort(&savePort);
  246.  
  247.     saveState = HGetState((Handle)cIconH);
  248.     HLock((Handle)cIconH);
  249.  
  250.     maskBitMap.rowBytes = (**cIconH).iconMask.rowBytes;
  251.     maskBitMap.bounds = (**cIconH).iconMask.bounds;
  252.     maskBitMap.baseAddr = (Ptr)(**cIconH).iconMaskData;
  253.  
  254.     err = SWCreateBestCGrafPort(&tempCGrafPort, &maskBitMap.bounds);
  255.  
  256.     if (err == noErr)
  257.     {
  258.         maskPixMapH = tempCGrafPort->portPixMap;
  259.         HLock((Handle)maskPixMapH);
  260.  
  261.         SetPort((GrafPtr)tempCGrafPort);
  262.  
  263.         CopyBits(&maskBitMap, (BitMapPtr)*maskPixMapH,
  264.                     &maskBitMap.bounds, &maskBitMap.bounds,
  265.                     srcCopy, NULL);
  266.  
  267.         HUnlock((Handle)maskPixMapH);
  268.  
  269.         *newCGrafPort = tempCGrafPort;
  270.     }
  271.  
  272.     HSetState((Handle)cIconH, saveState);
  273.     SetPort(savePort);
  274.  
  275.     return err;
  276. }
  277.  
  278.  
  279. ///--------------------------------------------------------------------------------------
  280. // SWCreateCGrafPortFromPict
  281. ///--------------------------------------------------------------------------------------
  282.  
  283. SW_PASCAL OSErr SWCreateCGrafPortFromPict(
  284.     CGrafPtr *newCGrafPort,
  285.     PicHandle srcPictH)
  286. {
  287.     OSErr err;
  288.     GrafPtr savePort;
  289.     GDHandle saveGDevice;
  290.     GWorldPtr tempCGrafPort;
  291.     PixMapHandle tempPixHdl;
  292.     Rect pictRect;
  293.  
  294.     *newCGrafPort = NULL;
  295.  
  296.     GetPort(&savePort);
  297.  
  298.     pictRect.left = 0;
  299.     pictRect.top = 0;
  300.     pictRect.right = (**srcPictH).picFrame.right - (**srcPictH).picFrame.left;
  301.     pictRect.bottom = (**srcPictH).picFrame.bottom - (**srcPictH).picFrame.top;
  302.  
  303.     err = SWCreateBestCGrafPort(&tempCGrafPort, &pictRect);
  304.  
  305.     if (err == noErr)
  306.     {
  307.         SetPort((GrafPtr)tempCGrafPort);
  308.  
  309.         DrawPicture(srcPictH, &pictRect);
  310.  
  311.         *newCGrafPort = tempCGrafPort;
  312.     }
  313.  
  314.     SetPort(savePort);
  315.  
  316.     return err;
  317. }
  318.  
  319.  
  320. ///--------------------------------------------------------------------------------------
  321. // SWCreateCGrafPortFromPictResource
  322. ///--------------------------------------------------------------------------------------
  323.  
  324. SW_PASCAL OSErr SWCreateCGrafPortFromPictResource(
  325.     CGrafPtr *newCGrafPort,
  326.     short pictResID)
  327. {
  328.     OSErr err = noErr;
  329.     PicHandle newPictH;
  330.  
  331.     *newCGrafPort = NULL;
  332.  
  333.     newPictH = GetPicture(pictResID);
  334.  
  335.     if (newPictH != NULL)
  336.     {
  337.         err = SWCreateCGrafPortFromPict(newCGrafPort, newPictH);
  338.  
  339.         ReleaseResource((Handle)newPictH);
  340.     }
  341.     else
  342.     {
  343.         err = ResError();
  344.  
  345.         if (err == noErr)
  346.         {
  347.             err = resNotFound;
  348.         }
  349.     }
  350.  
  351.     return err;
  352. }
  353.  
  354.  
  355. ///--------------------------------------------------------------------------------------
  356. // SWSetUpPixMap                                                    Adapted from code by Forrest Tanaka
  357. ///--------------------------------------------------------------------------------------
  358.  
  359. #define kDefaultRes 0x00480000 // Default resolution is 72 DPI; Fixed type
  360.  
  361. SW_PASCAL OSErr SWSetUpPixMap(
  362.     PixMapHandle    aPixMap,            // Handle to the PixMap being initialized
  363.     short                depth,            // Desired number of bits/pixel in off-screen
  364.     Rect                *bounds,            // Bounding rectangle of off-screen
  365.     CTabHandle        colors,            // Color table to assign to off-screen
  366.     short                bytesPerRow)    // Number of bytes per row in the PixMap
  367. {
  368.     CTabHandle    newColors;        // color table used for the off-screen PixMap
  369.     Ptr            offBaseAddr;    // pointer to the off-screen pixel image
  370.     OSErr            err;                // returns err code
  371.  
  372.     err = noErr;
  373.     newColors = NULL;
  374.     offBaseAddr = NULL;
  375.  
  376.         // clone the clut if indexed color; allocate a dummy clut if direct color
  377.     if (depth <= 8)
  378.     {
  379.         newColors = colors;
  380.         err = HandToHand( (Handle *)&newColors );
  381.     }
  382.     else
  383.     {
  384.         newColors = (CTabHandle)NewHandle(sizeof(ColorTable) - sizeof(CSpecArray));
  385.         err = MemError();
  386.     }
  387.  
  388.     if (err == noErr)
  389.     {
  390.             // allocate pixel image; long integer multiplication avoids overflow
  391.         offBaseAddr = NewPtr((Size)bytesPerRow *
  392.                                 (bounds->bottom - bounds->top) );
  393.         if (offBaseAddr != NULL)
  394.         {
  395.                 // initialize fields common to indexed and direct PixMaps
  396.             (**aPixMap).baseAddr = offBaseAddr;  // Point to image
  397.             (**aPixMap).rowBytes = bytesPerRow | // MSB set for PixMap
  398.                     0x8000;
  399.             (**aPixMap).bounds = *bounds;        // Use given bounds
  400.             (**aPixMap).pmVersion = 0;           // No special stuff
  401.             (**aPixMap).packType = 0;            // Default PICT pack
  402.             (**aPixMap).packSize = 0;            // Always zero in mem
  403.             (**aPixMap).hRes = kDefaultRes;      // 72 DPI default res
  404.             (**aPixMap).vRes = kDefaultRes;      // 72 DPI default res
  405.             (**aPixMap).pixelSize = depth;       // Set # bits/pixel
  406.             (**aPixMap).planeBytes = 0;          // Not used
  407.             (**aPixMap).pmReserved = 0;          // Not used
  408.  
  409.                 // initialize fields specific to indexed and direct PixMaps
  410.             if (depth <= 8)
  411.             {
  412.                     // PixMap is indexed
  413.                 (**aPixMap).pixelType = 0;            // Indicates indexed
  414.                 (**aPixMap).cmpCount = 1;            // Have 1 component
  415.                 (**aPixMap).cmpSize = depth;        // Component size=depth
  416.                 (**aPixMap).pmTable = newColors;    // Handle to CLUT
  417.             }
  418.             else
  419.             {
  420.                     // PixMap is direct
  421.                 (**aPixMap).pixelType = RGBDirect;    // Indicates direct
  422.                 (**aPixMap).cmpCount = 3;                // Have 3 components
  423.                 if (depth == 16)
  424.                     (**aPixMap).cmpSize = 5;            // 5 bits/component
  425.                 else
  426.                     (**aPixMap).cmpSize = 8;            // 8 bits/component
  427.                 (**newColors).ctSeed = 3 * (**aPixMap).cmpSize;
  428.                 (**newColors).ctFlags = 0;
  429.                 (**newColors).ctSize = 0;
  430.                 (**aPixMap).pmTable = newColors;
  431.             }
  432.         }
  433.         else
  434.             err = MemError();
  435.     }
  436.     else
  437.         newColors = NULL;
  438.  
  439.         // if no errors occurred, return a handle to the new off-screen PixMap
  440.     if (err != noErr)
  441.     {
  442.         if (newColors != NULL)
  443.             DisposCTable( newColors );
  444.     }
  445.  
  446.         // return the err code
  447.     return err;
  448. }
  449.  
  450.  
  451.  
  452. ///--------------------------------------------------------------------------------------
  453. // SWCreateGDevice                                                Adapted from code by Forrest Tanaka
  454. ///--------------------------------------------------------------------------------------
  455.  
  456. #define kITabRes 4 // Inverse-table resolution
  457.  
  458. SW_PASCAL OSErr SWCreateGDevice(
  459.     GDHandle            *retGDevice,    // returns a handle to the new GDevice
  460.     PixMapHandle    basePixMap)        // handle to the PixMap to base GDevice on
  461. {
  462.     GDHandle            newDevice;        // handle to the new GDevice
  463.     ITabHandle        embryoITab;        // handle to the embryonic inverse table
  464.     Rect                deviceRect;        // rectangle of GDevice
  465.     OSErr                err;                // error code
  466.  
  467.         // initialize a few things before we begin
  468.     err = noErr;
  469.     newDevice = NULL;
  470.     embryoITab = NULL;
  471.  
  472.         // allocate memory for the new GDevice
  473.     newDevice = (GDHandle)NewHandle( sizeof (GDevice) );
  474.     if (newDevice != NULL)
  475.     {
  476.             // allocate the embryonic inverse table
  477.         embryoITab = (ITabHandle)NewHandleClear( 2 );
  478.         if (embryoITab != NULL)
  479.         {
  480.                 // set rectangle of device to PixMap bounds
  481.             deviceRect = (**basePixMap).bounds;
  482.  
  483.             // Initialize the new GDevice fields
  484.             (**newDevice).gdRefNum = 0;                // Only used for screens
  485.             (**newDevice).gdID = 0;                        // Won’t normally use
  486.             if ((**basePixMap).pixelSize <= 8)
  487.                 (**newDevice).gdType = clutType;        // Depth≤8; clut device
  488.             else
  489.                 (**newDevice).gdType = directType;    // Depth>8; direct device
  490.             (**newDevice).gdITable = embryoITab;    // 2-byte handle for now
  491.             (**newDevice).gdResPref = kITabRes;        // Normal inv table res
  492.             (**newDevice).gdSearchProc = NULL;        // No color-search proc
  493.             (**newDevice).gdCompProc = NULL;            // No complement proc
  494.             (**newDevice).gdFlags = 0;                    // Will set these later
  495.             (**newDevice).gdPMap = basePixMap;        // Reference our PixMap
  496.             (**newDevice).gdRefCon = 0;                // Won’t normally use
  497.             (**newDevice).gdNextGD = NULL;            // Not in GDevice list
  498.             (**newDevice).gdRect = deviceRect;        // Use PixMap dimensions
  499.             (**newDevice).gdMode = -1;                    // For nonscreens
  500.             (**newDevice).gdCCBytes = 0;                // Only used for screens
  501.             (**newDevice).gdCCDepth = 0;                // Only used for screens
  502.             (**newDevice).gdCCXData = 0;                // Only used for screens
  503.             (**newDevice).gdCCXMask = 0;                // Only used for screens
  504.             (**newDevice).gdReserved = 0;                // Currently unused
  505.  
  506.                 // set color-device bit if PixMap isn’t black & white
  507.             if ((**basePixMap).pixelSize > 1)
  508.                 SetDeviceAttribute( newDevice, gdDevType, true );
  509.  
  510.                 // set bit to indicate that the GDevice has no video driver
  511.             SetDeviceAttribute( newDevice, noDriver, true );
  512.  
  513.                 // initialize the inverse table
  514.             if ((**basePixMap).pixelSize <= 8)
  515.             {
  516.                 MakeITable( (**basePixMap).pmTable, (**newDevice).gdITable, (**newDevice).gdResPref );
  517.                 err = QDError();
  518.             }
  519.         }
  520.         else
  521.             err = MemError();
  522.     }
  523.     else
  524.         err = MemError();
  525.  
  526.         // handle any errors along the way
  527.     if (err != noErr)
  528.     {
  529.         if (embryoITab != NULL)
  530.             DisposHandle( (Handle)embryoITab );
  531.         if (newDevice != NULL)
  532.             DisposHandle( (Handle)newDevice );
  533.     }
  534.     else
  535.         *retGDevice = newDevice;
  536.  
  537.         // return a handle to the new GDevice
  538.     return err;
  539. }
  540.  
  541.  
  542. ///--------------------------------------------------------------------------------------
  543. // SWDisposeCGrafPort                                            Adapted from code by Forrest Tanaka
  544. ///--------------------------------------------------------------------------------------
  545.  
  546. SW_PASCAL void SWDisposeCGrafPort(
  547.     CGrafPtr doomedPort)        // pointer to the CGrafPort to be disposed of
  548. {
  549.     CGrafPtr currPort;        // pointer to the current port
  550.  
  551.         // check to see whether the doomed CGrafPort is the current port
  552.     GetPort((GrafPtr *)&currPort);
  553.  
  554.     if (currPort == doomedPort)
  555.     {
  556.             // it is; set current port to Window Manager CGrafPort
  557.         GetCWMgrPort(&currPort);
  558.         SetPort((GrafPtr)currPort);
  559.     }
  560.  
  561.     DisposPtr((**doomedPort->portPixMap).baseAddr);
  562.  
  563.     if ((**doomedPort->portPixMap).pmTable != NULL)
  564.     {
  565.         DisposCTable((**doomedPort->portPixMap).pmTable);
  566.     }
  567.  
  568.     CloseCPort(doomedPort);
  569.     DisposPtr((Ptr)doomedPort);
  570. }
  571.  
  572.  
  573. ///--------------------------------------------------------------------------------------
  574. // SWCreateGrafPort                                            Adapted from code by Forrest Tanaka.
  575. ///--------------------------------------------------------------------------------------
  576.  
  577. SW_PASCAL OSErr SWCreateGrafPort(
  578.     GrafPtr* newPort,
  579.     Rect* newPortRect)
  580. {
  581.     OSErr err = noErr;
  582.     GrafPtr savePort;        // save port for later restore
  583.     GrafPtr localPort;    // local copy of GrafPort
  584.     Rect localPortRect;    // local copy of bounds
  585.  
  586.     *newPort = NULL;
  587.  
  588.         // save off the current port
  589.     GetPort(&savePort);
  590.  
  591.         // set the top-left corner of bounds to (0,0)
  592.     localPortRect = *newPortRect;
  593.     OffsetRect(&localPortRect, -newPortRect->left, -newPortRect->top);
  594.  
  595.         // allocate a new GrafPort
  596.     localPort = (GrafPtr)NewPtrClear(sizeof(GrafPort));
  597.  
  598.     if (localPort != NULL)
  599.     {
  600.             // initialize the new port and make the current port
  601.         OpenPort(localPort);
  602.         SetPort(localPort);
  603.         ForeColor(blackColor);
  604.         BackColor(whiteColor);
  605.  
  606.             // initialize and allocate the bitmap
  607.         localPort->portBits.bounds = localPortRect;
  608.           localPort->portBits.rowBytes = ((localPortRect.right + 15) >> 4) << 1;
  609.         localPort->portBits.baseAddr = NewPtrClear(localPort->portBits.rowBytes *
  610.                                                                 (long)localPortRect.bottom);
  611.  
  612.         if (localPort->portBits.baseAddr != NULL)
  613.         {
  614.                 // clean up the new port
  615.             localPort->portRect = localPortRect;
  616.             ClipRect(&localPortRect);
  617.             RectRgn(localPort->visRgn, &localPortRect);
  618.             EraseRect(&localPortRect);
  619.  
  620.             *newPort = localPort;
  621.         }
  622.         else // allocation failed
  623.         {
  624.                 // capture the error
  625.             err = MemError();
  626.  
  627.                 // deallocate the port
  628.             ClosePort(localPort);
  629.             DisposPtr((Ptr)localPort);
  630.         }
  631.     }
  632.     else
  633.     {
  634.         err = MemError();
  635.     }
  636.  
  637.     SetPort(savePort);
  638.  
  639.     return err;
  640. }
  641.  
  642.  
  643. ///--------------------------------------------------------------------------------------
  644. // SWCreateGrafPortFromCIconMask
  645. ///--------------------------------------------------------------------------------------
  646.  
  647. SW_PASCAL OSErr SWCreateGrafPortFromCIconMask(
  648.     GrafPtr *newGrafPort,
  649.     CIconHandle cIconH)
  650. {
  651.     OSErr err;
  652.     GrafPtr savePort;
  653.     char saveState;
  654.     GrafPtr tempGrafPort;
  655.     BitMap maskBitMap;
  656.  
  657.     *newGrafPort = NULL;
  658.  
  659.     GetPort(&savePort);
  660.  
  661.     saveState = HGetState((Handle)cIconH);
  662.     HLock((Handle)cIconH);
  663.  
  664.     maskBitMap.rowBytes = (**cIconH).iconMask.rowBytes;
  665.     maskBitMap.bounds = (**cIconH).iconMask.bounds;
  666.     maskBitMap.baseAddr = (Ptr)(**cIconH).iconMaskData;
  667.  
  668.     err = SWCreateGrafPort(&tempGrafPort, &maskBitMap.bounds);
  669.  
  670.     if (err == noErr)
  671.     {
  672.         SetPort(tempGrafPort);
  673.  
  674.         CopyBits(&maskBitMap, &tempGrafPort->portBits,
  675.                     &maskBitMap.bounds, &maskBitMap.bounds,
  676.                     srcCopy, NULL);
  677.  
  678.         *newGrafPort = tempGrafPort;
  679.     }
  680.  
  681.     HSetState((Handle)cIconH, saveState);
  682.     SetPort(savePort);
  683.  
  684.     return err;
  685. }
  686.  
  687.  
  688. ///--------------------------------------------------------------------------------------
  689. // SWCreateGrafPortFromPict
  690. ///--------------------------------------------------------------------------------------
  691.  
  692. SW_PASCAL OSErr SWCreateGrafPortFromPict(
  693.     GrafPtr *offScrnPort,
  694.     PicHandle srcPictH)
  695. {
  696.     OSErr            err;
  697.     GrafPtr        savePort;
  698.     Rect            tmpRect;
  699.  
  700.     GetPort(&savePort);
  701.  
  702.     tmpRect.left = tmpRect.top = 0;
  703.     tmpRect.right = (**srcPictH).picFrame.right - (**srcPictH).picFrame.left;
  704.     tmpRect.bottom = (**srcPictH).picFrame.bottom - (**srcPictH).picFrame.top;
  705.  
  706.         //    create a port
  707.     err = SWCreateGrafPort(offScrnPort, &tmpRect);
  708.  
  709.     if (err == noErr)
  710.     {
  711.         SetPort(*offScrnPort);
  712.  
  713.             //    draw the picture
  714.         DrawPicture(srcPictH, &tmpRect);
  715.     }
  716.  
  717.     SetPort(savePort);
  718.  
  719.     return err;
  720. }
  721.  
  722. ///--------------------------------------------------------------------------------------
  723. // SWCreateGrafPortFromPictResource
  724. //
  725. //    this routine will set up an offscreen port, and draw a pict into it
  726. //    the offscreen port is the exact size of the pict
  727. ///--------------------------------------------------------------------------------------
  728.  
  729. SW_PASCAL OSErr SWCreateGrafPortFromPictResource(
  730.     GrafPtr *offScrnPort,
  731.     short pictResID)
  732. {
  733.     OSErr            err;
  734.     GrafPtr        savePort;
  735.     PicHandle    newPictH;
  736.  
  737.     GetPort(&savePort);
  738.  
  739.     newPictH = GetPicture(pictResID);
  740.  
  741.     if (newPictH != NULL)
  742.     {
  743.         err = SWCreateGrafPortFromPict(offScrnPort, newPictH);
  744.  
  745.         ReleaseResource((Handle)newPictH);
  746.     }
  747.     else
  748.     {
  749.         err = ResError();
  750.  
  751.         if (err == noErr)
  752.         {
  753.             err = resNotFound;
  754.         }
  755.     }
  756.  
  757.     SetPort(savePort);
  758.  
  759.     return err;
  760. }
  761.  
  762.  
  763. ///--------------------------------------------------------------------------------------
  764. // SWDisposeGrafPort                                            Adapted from code by Forrest Tanaka.
  765. ///--------------------------------------------------------------------------------------
  766.  
  767. SW_PASCAL void SWDisposeGrafPort(
  768.     GrafPtr doomedPort)
  769. {
  770.     ClosePort(doomedPort);
  771.     DisposPtr(doomedPort->portBits.baseAddr);
  772.     DisposPtr((Ptr)doomedPort);
  773. }
  774.  
  775.  
  776. ///--------------------------------------------------------------------------------------
  777. // SWCreateRegionFromCIconMask
  778. ///--------------------------------------------------------------------------------------
  779.  
  780. SW_PASCAL OSErr SWCreateRegionFromCIconMask(
  781.     RgnHandle *maskRgn,
  782.     CIconHandle cIconH)
  783. {
  784.     OSErr err = noErr;
  785.     RgnHandle tempMaskRgn;
  786.     char saveState;
  787.     BitMap iconMask;
  788.  
  789.     *maskRgn = NULL;
  790.  
  791.     saveState = HGetState((Handle)cIconH);
  792.     HLock((Handle)cIconH);
  793.  
  794.     iconMask.rowBytes = (**cIconH).iconMask.rowBytes;
  795.     iconMask.bounds = (**cIconH).iconMask.bounds;
  796.     iconMask.baseAddr = (Ptr)(**cIconH).iconMaskData;
  797.  
  798.     tempMaskRgn = NewRgn();
  799.  
  800.     if (tempMaskRgn != NULL)
  801.     {
  802.         if (SWHasGWorlds())
  803.         {
  804.             err = BitMapToRegion(tempMaskRgn, &iconMask);
  805.         }
  806.         else
  807.         {
  808.             err = BitMapToRegionGlue(tempMaskRgn, &iconMask);
  809.         }
  810.  
  811.         if (err == noErr)
  812.         {
  813.             *maskRgn = tempMaskRgn;
  814.         }
  815.         else
  816.         {
  817.             DisposeRgn(tempMaskRgn);
  818.         }
  819.     }
  820.     else
  821.     {
  822.         err = MemError();
  823.     }
  824.  
  825.     HSetState((Handle)cIconH, saveState);
  826.  
  827.     return err;
  828. }
  829.  
  830.  
  831. ///--------------------------------------------------------------------------------------
  832. // SWCreateRegionFromPict
  833. ///--------------------------------------------------------------------------------------
  834.  
  835. SW_PASCAL OSErr SWCreateRegionFromPict(
  836.     RgnHandle *pictRgnH,
  837.     PicHandle srcPictH)
  838. {
  839.     OSErr err;
  840.     RgnHandle tempRgnH;
  841.     GrafPtr savePort, offScrnPort;
  842.  
  843.     *pictRgnH = NULL;
  844.  
  845.     GetPort(&savePort);
  846.  
  847.     err = SWCreateGrafPortFromPict(&offScrnPort, srcPictH);
  848.  
  849.     if (err == noErr)
  850.     {
  851.         SetPort(offScrnPort);
  852.  
  853.         tempRgnH = NewRgn();
  854.  
  855.         if (tempRgnH != NULL)
  856.         {
  857.             if (SWHasGWorlds())
  858.             {
  859.                 err = BitMapToRegion(tempRgnH, &offScrnPort->portBits);
  860.             }
  861.             else
  862.             {
  863.                 err = BitMapToRegionGlue(tempRgnH, &offScrnPort->portBits);
  864.             }
  865.  
  866.             if (err == noErr)
  867.             {
  868.                 *pictRgnH = tempRgnH;
  869.             }
  870.             else
  871.             {
  872.                 DisposeRgn(tempRgnH);
  873.             }
  874.         }
  875.         else
  876.         {
  877.             err = MemError();
  878.         }
  879.  
  880.         SetPort(savePort);
  881.         SWDisposeGrafPort(offScrnPort);
  882.     }
  883.  
  884.     return err;
  885. }
  886.  
  887.  
  888. ///--------------------------------------------------------------------------------------
  889. // SWCreateRegionFromPictResource
  890. ///--------------------------------------------------------------------------------------
  891.  
  892. SW_PASCAL OSErr SWCreateRegionFromPictResource(
  893.     RgnHandle *pictRgnH,
  894.     short pictResID)
  895. {
  896.     OSErr            err;
  897.     PicHandle    newPictH;
  898.  
  899.     newPictH = GetPicture(pictResID);
  900.  
  901.     if (newPictH != NULL)
  902.     {
  903.         err = SWCreateRegionFromPict(pictRgnH, newPictH);
  904.  
  905.         ReleaseResource((Handle)newPictH);
  906.     }
  907.     else
  908.     {
  909.         err = ResError();
  910.  
  911.         if (err == noErr)
  912.         {
  913.             err = resNotFound;
  914.         }
  915.     }
  916.  
  917.     return err;
  918. }
  919.  
  920.  
  921. ///--------------------------------------------------------------------------------------
  922. // SWGetCIcon
  923. ///--------------------------------------------------------------------------------------
  924.  
  925. SW_PASCAL OSErr SWGetCIcon(
  926.     CIconHandle* cIconH,
  927.     short iconResID)
  928. {
  929.     OSErr err = noErr;
  930.     CIconHandle tempCIconH;
  931.  
  932.     *cIconH = NULL;
  933.  
  934.     if (SWHasColorQuickDraw())
  935.     {
  936.         tempCIconH = GetCIcon(iconResID);
  937.  
  938.         if (tempCIconH == NULL)
  939.         {
  940.                 // hmmm, could be a resource error...
  941.             err = ResError();
  942.  
  943.             if (err == noErr)
  944.             {
  945.                     // or, a memory error...
  946.                 err = MemError();
  947.             }
  948.  
  949.             if (err == noErr)
  950.             {
  951.                     // ...well then lets make up an error!
  952.                 err = resNotFound;
  953.             }
  954.         }
  955.     }
  956.     else
  957.     {
  958.             // don't ever do this if color QuickDraw is around!
  959.         tempCIconH = (CIconHandle)GetResource('cicn', iconResID);
  960.  
  961.         if (tempCIconH != NULL)
  962.         {
  963.             DetachResource((Handle)tempCIconH);
  964.         }
  965.         else
  966.         {
  967.             err = ResError();
  968.  
  969.             if (err == noErr)
  970.             {
  971.                 err = resNotFound;
  972.             }
  973.         }
  974.     }
  975.  
  976.     if (err == noErr)
  977.     {
  978.         *cIconH = tempCIconH;
  979.     }
  980.  
  981.     return err;
  982. }
  983.  
  984.  
  985. ///--------------------------------------------------------------------------------------
  986. // SWPlotCIcon
  987. ///--------------------------------------------------------------------------------------
  988.  
  989. SW_PASCAL OSErr SWPlotCIcon(
  990.     CIconHandle cIconH,
  991.     Rect* iconRect)
  992. {
  993.     OSErr err;
  994.     char saveState;
  995.     BitMap iconBitMap, maskBitMap;
  996.     GrafPtr curPort;
  997.  
  998.     if (SWHasColorQuickDraw())
  999.     {
  1000.         PlotCIcon(iconRect, cIconH);
  1001.     }
  1002.     else
  1003.     {
  1004.         saveState = HGetState((Handle)cIconH);
  1005.         HLock((Handle)cIconH);
  1006.  
  1007.         maskBitMap.rowBytes = (**cIconH).iconMask.rowBytes;
  1008.         maskBitMap.bounds = (**cIconH).iconMask.bounds;
  1009.         maskBitMap.baseAddr = (Ptr)(**cIconH).iconMaskData;
  1010.  
  1011.         iconBitMap.rowBytes = (**cIconH).iconBMap.rowBytes;
  1012.         iconBitMap.bounds = (**cIconH).iconBMap.bounds;
  1013.         iconBitMap.baseAddr = maskBitMap.baseAddr +
  1014.                 (maskBitMap.rowBytes * (maskBitMap.bounds.bottom - maskBitMap.bounds.top));
  1015.  
  1016.         GetPort(&curPort);
  1017.  
  1018.         CopyMask(&iconBitMap, &maskBitMap, &curPort->portBits,
  1019.                 &iconBitMap.bounds, &maskBitMap.bounds, iconRect);
  1020.  
  1021.         HSetState((Handle)cIconH, saveState);
  1022.     }
  1023.     
  1024.     return err;
  1025. }
  1026.  
  1027.  
  1028. ///--------------------------------------------------------------------------------------
  1029. // SWPlotCIcon
  1030. ///--------------------------------------------------------------------------------------
  1031.  
  1032. SW_PASCAL void SWDisposeCIcon(
  1033.     CIconHandle cIconH)
  1034. {
  1035.     if (SWHasColorQuickDraw())
  1036.     {
  1037.         DisposeCIcon(cIconH);
  1038.     }
  1039.     else
  1040.     {
  1041.         DisposeHandle((Handle)cIconH);
  1042.     }
  1043. }
  1044.  
  1045.  
  1046. ///--------------------------------------------------------------------------------------
  1047. // SWCreateOptimumGWorld
  1048. //
  1049. //    create a new GWorld optimized for speed in copying
  1050. //    to the graphics device that intersects the given rect.
  1051. ///--------------------------------------------------------------------------------------
  1052.  
  1053. SW_PASCAL OSErr SWCreateOptimumGWorld(
  1054.     GWorldPtr *optGWorld,
  1055.     Rect *devRect)
  1056. {
  1057.     OSErr err;
  1058.     CGrafPtr saveCPort;
  1059.     GDHandle saveGDevice;
  1060.     GWorldPtr tempGWorld;
  1061.     PixMapHandle pixMapH;
  1062.     Rect tempRect = *devRect;
  1063.  
  1064.     *optGWorld = NULL;
  1065.  
  1066.     GetGWorld(&saveCPort, &saveGDevice);
  1067.  
  1068.     LocalToGlobal((Point *)&tempRect.top);
  1069.     LocalToGlobal((Point *)&tempRect.bottom);
  1070.  
  1071.     err = NewGWorld(&tempGWorld, 0, &tempRect, NULL, NULL, noNewDevice);
  1072.  
  1073.     if (err == noErr)
  1074.     {
  1075.         SetGWorld(tempGWorld, NULL);
  1076.  
  1077.         pixMapH = GetGWorldPixMap(tempGWorld);
  1078.  
  1079.         if (LockPixels(pixMapH))
  1080.         {
  1081.             EraseRect(&tempGWorld->portRect);
  1082.  
  1083.             UnlockPixels(pixMapH);
  1084.         }
  1085.  
  1086.         *optGWorld = tempGWorld;
  1087.     }
  1088.  
  1089.     SetGWorld(saveCPort, saveGDevice);
  1090.  
  1091.     return err;
  1092. }
  1093.  
  1094.  
  1095. ///--------------------------------------------------------------------------------------
  1096. // SWCreateGWorldFromPict
  1097. //
  1098. //    creates a offScreen GWorld and draws the specified pict into it
  1099. ///--------------------------------------------------------------------------------------
  1100.  
  1101. SW_PASCAL OSErr SWCreateGWorldFromPict(
  1102.     GWorldPtr *pictGWorld,
  1103.     PicHandle pictH)
  1104. {
  1105.     OSErr err;
  1106.     CGrafPtr saveCPort;
  1107.     GDHandle saveGDevice;
  1108.     GWorldPtr tempGWorld;
  1109.     PixMapHandle tempPixHdl;
  1110.     Rect pictRect;
  1111.  
  1112.     *pictGWorld = NULL;
  1113.  
  1114.     GetGWorld(&saveCPort, &saveGDevice);
  1115.  
  1116.     pictRect.left = 0;
  1117.     pictRect.top = 0;
  1118.     pictRect.right = (**pictH).picFrame.right - (**pictH).picFrame.left;
  1119.     pictRect.bottom = (**pictH).picFrame.bottom - (**pictH).picFrame.top;
  1120.  
  1121.     err = SWCreateOptimumGWorld(&tempGWorld, &pictRect);
  1122.  
  1123.     if (err == noErr)
  1124.     {
  1125.         *pictGWorld = tempGWorld;
  1126.  
  1127.         SetGWorld(tempGWorld, NULL);
  1128.  
  1129.         tempPixHdl = GetGWorldPixMap(tempGWorld);
  1130.  
  1131.         if (LockPixels(tempPixHdl))
  1132.         {
  1133.             DrawPicture(pictH, &pictRect);
  1134.  
  1135.             UnlockPixels(tempPixHdl);
  1136.         }
  1137.     }
  1138.  
  1139.     SetGWorld(saveCPort, saveGDevice);
  1140.  
  1141.     return err;
  1142. }
  1143.  
  1144.  
  1145. ///--------------------------------------------------------------------------------------
  1146. // SWCreateGWorldFromPictResource
  1147. ///--------------------------------------------------------------------------------------
  1148.  
  1149. SW_PASCAL OSErr SWCreateGWorldFromPictResource(
  1150.     GWorldPtr *pictGWorldP,
  1151.     short pictResID)
  1152. {
  1153.     OSErr err = noErr;
  1154.     PicHandle newPictH;
  1155.  
  1156.     newPictH = GetPicture(pictResID);
  1157.  
  1158.     if (newPictH != NULL)
  1159.     {
  1160.         err = SWCreateGWorldFromPict(pictGWorldP, newPictH);
  1161.  
  1162.         ReleaseResource((Handle)newPictH);
  1163.     }
  1164.     else
  1165.     {
  1166.         err = ResError();
  1167.         
  1168.         if (err == noErr)
  1169.         {
  1170.             err = resNotFound;
  1171.         }
  1172.     }
  1173.  
  1174.     return err;
  1175. }
  1176.  
  1177.  
  1178. ///--------------------------------------------------------------------------------------
  1179. // SWCreateGWorldFromCIconResource
  1180. ///--------------------------------------------------------------------------------------
  1181.  
  1182. SW_PASCAL OSErr SWCreateGWorldFromCIconResource(
  1183.     GWorldPtr *iconGWorldP,
  1184.     short iconResID)
  1185. {
  1186.     OSErr err;
  1187.     CIconHandle cIconH;
  1188.  
  1189.     cIconH = GetCIcon(iconResID);
  1190.  
  1191.     if (cIconH != NULL)
  1192.     {
  1193.         HNoPurge((Handle)cIconH);
  1194.  
  1195.         if (iconGWorldP != NULL)
  1196.         {
  1197.             err = SWCreateGWorldFromCIcon(iconGWorldP, cIconH);
  1198.         }
  1199.  
  1200.         DisposeCIcon(cIconH);
  1201.     }
  1202.  
  1203.     return err;
  1204. }
  1205.  
  1206.  
  1207. ///--------------------------------------------------------------------------------------
  1208. // SWCreateGWorldFromCIcon
  1209. ///--------------------------------------------------------------------------------------
  1210.  
  1211. SW_PASCAL OSErr SWCreateGWorldFromCIcon(
  1212.     GWorldPtr *iconGWorldP,
  1213.     CIconHandle cIconH)
  1214. {
  1215.     OSErr err;
  1216.     CGrafPtr saveCPort;
  1217.     GDHandle saveGDevice;
  1218.     char saveState;
  1219.     GWorldPtr tempGWorldP;
  1220.     PixMapHandle iconPixMapH;
  1221.     Rect iconRect;
  1222.  
  1223.     *iconGWorldP = NULL;
  1224.  
  1225.     GetGWorld(&saveCPort, &saveGDevice);
  1226.  
  1227.     iconRect = (**cIconH).iconPMap.bounds;
  1228.     
  1229.     err = SWCreateOptimumGWorld(&tempGWorldP, &iconRect);
  1230.  
  1231.     if (err == noErr)
  1232.     {
  1233.         *iconGWorldP = tempGWorldP;
  1234.  
  1235.         SetGWorld(tempGWorldP, NULL);
  1236.  
  1237.         iconPixMapH = GetGWorldPixMap(tempGWorldP);
  1238.  
  1239.         if (LockPixels(iconPixMapH))
  1240.         {
  1241.             PlotCIcon(&iconRect, cIconH);
  1242.  
  1243.             UnlockPixels(iconPixMapH);
  1244.         }
  1245.     }
  1246.  
  1247.     SetGWorld(saveCPort, saveGDevice);
  1248.  
  1249.     return err;
  1250. }
  1251.  
  1252.  
  1253. ///--------------------------------------------------------------------------------------
  1254. // SWCreateGWorldFromCIconMask
  1255. ///--------------------------------------------------------------------------------------
  1256.  
  1257. SW_PASCAL OSErr SWCreateGWorldFromCIconMask(
  1258.     GWorldPtr *maskGWorldP,
  1259.     CIconHandle cIconH)
  1260. {
  1261.     OSErr err;
  1262.     CGrafPtr saveCPort;
  1263.     GDHandle saveGDevice;
  1264.     char saveState;
  1265.     BitMap maskBitMap;
  1266.     GWorldPtr tempGWorldP;
  1267.     PixMapHandle maskPixMapH;
  1268.  
  1269.     GetGWorld(&saveCPort, &saveGDevice);
  1270.  
  1271.     saveState = HGetState((Handle)cIconH);
  1272.     HLock((Handle)cIconH);
  1273.  
  1274.     maskBitMap.rowBytes = (**cIconH).iconMask.rowBytes;
  1275.     maskBitMap.bounds = (**cIconH).iconMask.bounds;
  1276.     maskBitMap.baseAddr = (Ptr)(**cIconH).iconMaskData;
  1277.  
  1278.     err = SWCreateOptimumGWorld(&tempGWorldP, &maskBitMap.bounds);
  1279.  
  1280.     if (err == noErr)
  1281.     {
  1282.         *maskGWorldP = tempGWorldP;
  1283.  
  1284.         SetGWorld(tempGWorldP, NULL);
  1285.  
  1286.         maskPixMapH = GetGWorldPixMap(tempGWorldP);
  1287.  
  1288.         if (LockPixels(maskPixMapH))
  1289.         {
  1290.             CopyBits(&maskBitMap, (BitMapPtr)*maskPixMapH,
  1291.                         &maskBitMap.bounds, &maskBitMap.bounds,
  1292.                         srcCopy, NULL);
  1293.  
  1294.             UnlockPixels(maskPixMapH);
  1295.         }
  1296.     }
  1297.  
  1298.     SetGWorld(saveCPort, saveGDevice);
  1299.  
  1300.     HSetState((Handle)cIconH, saveState);
  1301.  
  1302.     return err;
  1303. }
  1304.  
  1305.  
  1306. ///--------------------------------------------------------------------------------------
  1307. // SWHasColorQuickDraw
  1308. ///--------------------------------------------------------------------------------------
  1309.  
  1310. SW_PASCAL Boolean SWHasColorQuickDraw(void)
  1311. {
  1312.     OSErr err;
  1313.     long    gestaltResult;
  1314.  
  1315.     err = Gestalt(gestaltQuickdrawVersion, &gestaltResult);
  1316.  
  1317.     return (err == noErr) && (gestaltResult >= gestalt8BitQD);
  1318. }
  1319.  
  1320.  
  1321. ///--------------------------------------------------------------------------------------
  1322. // SWHasGWorlds
  1323. ///--------------------------------------------------------------------------------------
  1324.  
  1325. SW_PASCAL Boolean SWHasGWorlds(void)
  1326. {
  1327.     OSErr err;
  1328.     long    gestaltResult;
  1329.  
  1330.     err = Gestalt(gestaltQuickdrawVersion, &gestaltResult);
  1331.  
  1332.     return (err == noErr) && (((gestaltResult > gestaltOriginalQD) &&
  1333.             (gestaltResult < gestalt8BitQD)) || (gestaltResult >= gestalt32BitQD));
  1334. }
  1335.